package org.cliff.message.platform.demo.util;

import java.io.*;
import java.nio.charset.StandardCharsets;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;
import org.xml.sax.InputSource;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

public class XmlHelper {


    public static String beanToXml(Object obj) throws JAXBException {
        StringWriter sw = new StringWriter();
        //MessageListVO: 最外层对象类
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        //设置编码格式
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        //设置按照xml格式化输出
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        //输出在控制台
        marshaller.marshal(obj, sw);
        return sw.toString();
    }

    public static <T> T convertXmlStrToObject(Class<T> clazz, String xmlStr) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(clazz);
        // 进行将Xml转成对象的核心接口
        Unmarshaller unmarshaller = context.createUnmarshaller();
        StringReader sr = new StringReader(xmlStr);
        return (T) unmarshaller.unmarshal(sr);
    }


    /**
     * XML格式转Bean对象
     *
     * @param request http请求对象
     * @param xPath   需要取的节点路径
     * @param clazz   需要转换的对象
     * @param <T>     泛型对象
     * @return 对象信息
     * @throws IOException       文件读取异常
     * @throws DocumentException XML文档处理异常
     */
    public static <T> T xmlToBean(HttpServletRequest request, String xPath, Class<T> clazz) throws IOException, DocumentException {
        InputSource source = new InputSource(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
        Node node = read(source, xPath);
        String xml = node.asXML();
        ObjectMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
        xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
        return xmlMapper.readValue(xml, clazz);
    }

    /**
     * XML格式转JSON
     *
     * @param request Http请求
     * @param xPath   需要取的节点路径
     * @return JSON串
     * @throws IOException       文件读取异常
     * @throws DocumentException XML文档建立异常
     */
    public static String xmlToJson(HttpServletRequest request, String xPath) throws IOException, DocumentException {
        InputSource source = new InputSource(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
        Node node = read(source, xPath);
        String xml = node.asXML();
        ObjectMapper xmlMapper = new XmlMapper();
        JsonNode jsonNode = xmlMapper.readTree(xml);
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(jsonNode);
    }

    /**
     * 基于XPath获取某个节点信息
     *
     * @param is 数据流
     * @return 某个节点信息
     * @throws DocumentException 异常信息
     */
    public static Node read(InputSource is, String xPath) throws DocumentException {
        SAXReader reader = new SAXReader();
        reader.setEncoding(StandardCharsets.UTF_8.name());
        Document document = reader.read(is);
        document.setXMLEncoding("utf-8");
        document.accept(new NameSpaceClean());
        return document.selectSingleNode(xPath);
    }

    /**
     * 用于去除命名空间，保持存储的xml格式
     */
    static final class NameSpaceClean extends VisitorSupport {
        public void visit(Attribute node) {
            if (node.toString().contains("xmlns") || node.toString().contains("xsi:")) {
                node.detach();
            }
        }

        public void visit(Namespace namespace) {
            namespace.detach();
        }

        public void visit(Document document) {
            ((DefaultElement) document.getRootElement()).setNamespace(Namespace.NO_NAMESPACE);
            document.getRootElement().additionalNamespaces().clear();
        }

        public void visit(Element element) {
            if (element instanceof DefaultElement) {
                //去除每个节点的命名空间
                ((DefaultElement) element).setNamespace(Namespace.NO_NAMESPACE);
                element.getNamespace().detach();
            }
            //清除属性值
            int attrCount = element.attributeCount();
            for (int i = 0; i < attrCount; i++) {
                element.remove(element.attribute(0));
            }
        }
    }
}
